format ELF64 executable 3
entry Main

RTLD_LAZY               = 1

SDL_KEYDOWN             = 2
SDL_INIT_VIDEO          = 0x00000020
SDL_OPENGL              = 0x00000002
SDL_NOFRAME             = 0x00000020
SDL_GL_DOUBLEBUFFER     = 5

GL_COLOR_BUFFER_BIT                 = 0x00004000
GL_VERTEX_PROGRAM_ARB               = 0x8620
GL_FRAGMENT_PROGRAM_ARB             = 0x8804
GL_PROGRAM_FORMAT_ASCII_ARB         = 0x8875
GL_STATIC_DRAW                      = 0x88E4
GL_BUFFER_GPU_ADDRESS_NV            = 0x8F1D
GL_READ_ONLY                        = 0x88B8
GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV   = 0x8F1E
GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV   = 0x8F20
GL_FALSE                            = 0
GL_TRUE                             = 1
GL_TRIANGLES                        = 0x0004
GL_FLOAT                            = 0x1406

include                 'import64.inc'
interpreter             '/lib64/ld-linux-x86-64.so.2'
needed                  'libdl.so.2'
import                  dlopen,dlsym

;-------------------------------------------------------------------------------
; NAME:     ldsdlf
;-------------------------------------------------------------------------------
macro       ldsdlf      name* {
            mov         rdi,[g_libSDL]
            mov         rsi,g_str_#name
            call        [dlsym]
            mov         [name],rax
}
;-------------------------------------------------------------------------------
; NAME:     ldglf
;-------------------------------------------------------------------------------
macro       ldglf       name* {
            mov         rdi,g_str_#name
            call        [SDL_GL_GetProcAddress]
            mov         [name],rax
}

segment readable executable

;-------------------------------------------------------------------------------
; NAME:     LoadSDLFunctions
;-------------------------------------------------------------------------------
LoadSDLFunctions:
            sub         rsp,8
            ; load SDL 1.2 library
            mov         rdi,g_str_libsdl
            mov         esi,RTLD_LAZY
            call        [dlopen]
            mov         [g_libSDL],rax
            ; load SDL functions
            ldsdlf      SDL_Init
            ldsdlf      SDL_Quit
            ldsdlf      SDL_SetVideoMode
            ldsdlf      SDL_PollEvent
            ldsdlf      SDL_GetTicks
            ldsdlf      SDL_GL_SwapBuffers
            ldsdlf      SDL_GL_GetProcAddress
            ldsdlf      SDL_GL_SetAttribute
            ldsdlf      SDL_GL_LoadLibrary
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     OpenWindow
;-------------------------------------------------------------------------------
OpenWindow:
            sub         rsp,8
            ; call SDL_Init
            mov         edi,SDL_INIT_VIDEO
            call        [SDL_Init]
            ; call SDL_GL_SetAttribute
            mov         edi,SDL_GL_DOUBLEBUFFER
            mov         esi,1
            call        [SDL_GL_SetAttribute]
            ; call SDL_GL_LoadLibrary
            xor         edi,edi
            call        [SDL_GL_LoadLibrary]
            ; call SDL_SetVideoMode
            mov         edi,800
            mov         esi,800
            xor         edx,edx
            mov         ecx,SDL_OPENGL+SDL_NOFRAME
            call        [SDL_SetVideoMode]
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     LoadOGLFunctions
;-------------------------------------------------------------------------------
LoadOGLFunctions:
            sub         rsp,8
            ldglf       glClear
            ldglf       glGenProgramsARB
            ldglf       glBindProgramARB
            ldglf       glNamedProgramStringEXT
            ldglf       glGenBuffers
            ldglf       glNamedBufferDataEXT
            ldglf       glGetNamedBufferParameterui64vNV
            ldglf       glMakeNamedBufferResidentNV
            ldglf       glEnable
            ldglf       glEnableClientState
            ldglf       glVertexAttribFormatNV
            ldglf       glEnableVertexAttribArray
            ldglf       glBufferAddressRangeNV
            ldglf       glDrawArrays
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     Init
;-------------------------------------------------------------------------------
Init:
            sub         rsp,8
            ; create vertex program
            mov         edi,1
            mov         rsi,g_VP
            call        [glGenProgramsARB]
            mov         edi,[g_VP]
            mov         esi,GL_VERTEX_PROGRAM_ARB
            mov         edx,GL_PROGRAM_FORMAT_ASCII_ARB
            mov         ecx,SRC_VP_LENGTH
            mov         r8,g_SrcVP
            call        [glNamedProgramStringEXT]
            ; create fragment program
            mov         edi,1
            mov         rsi,g_FP
            call        [glGenProgramsARB]
            mov         edi,[g_FP]
            mov         esi,GL_FRAGMENT_PROGRAM_ARB
            mov         edx,GL_PROGRAM_FORMAT_ASCII_ARB
            mov         ecx,SRC_FP_LENGTH
            mov         r8,g_SrcFP
            call        [glNamedProgramStringEXT]
            ; create vertex buffer
            mov         edi,1
            mov         rsi,g_VBO
            call        [glGenBuffers]
            mov         edi,[g_VBO]
            mov         esi,VBO_SIZE
            mov         rdx,g_VertexData
            mov         ecx,GL_STATIC_DRAW
            call        [glNamedBufferDataEXT]
            ; get vbo address
            mov         edi,[g_VBO]
            mov         esi,GL_BUFFER_GPU_ADDRESS_NV
            mov         rdx,g_VBOAddr
            call        [glGetNamedBufferParameterui64vNV]
            mov         edi,[g_VBO]
            mov         esi,GL_READ_ONLY
            call        [glMakeNamedBufferResidentNV]
            ; set GL state
            mov         edi,GL_VERTEX_PROGRAM_ARB
            call        [glEnable]
            mov         edi,GL_FRAGMENT_PROGRAM_ARB
            call        [glEnable]
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     Update
;-------------------------------------------------------------------------------
Update:
            sub         rsp,8
            ; clear color buffer
            mov         edi,GL_COLOR_BUFFER_BIT
            call        [glClear]
            ; bind programs
            mov         edi,GL_VERTEX_PROGRAM_ARB
            mov         esi,[g_VP]
            call        [glBindProgramARB]
            mov         edi,GL_FRAGMENT_PROGRAM_ARB
            mov         esi,[g_FP]
            call        [glBindProgramARB]
            ; enable vertex arrays
            mov         edi,GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV
            call        [glEnableClientState]
            mov         edi,0
            call        [glEnableVertexAttribArray]
            ; set vertex array format
            mov         edi,0
            mov         esi,2
            mov         edx,GL_FLOAT
            mov         ecx,GL_FALSE
            mov         r8d,0
            call        [glVertexAttribFormatNV]
            ; set vertex array address
            mov         edi,GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV
            mov         esi,0
            mov         rdx,[g_VBOAddr]
            mov         ecx,VBO_SIZE
            call        [glBufferAddressRangeNV]
            ; draw
            mov         edi,GL_TRIANGLES
            mov         esi,0
            mov         edx,3
            call        [glDrawArrays]
            add         rsp,8
            ret
;-------------------------------------------------------------------------------
; NAME:     RunMainLoop
;-------------------------------------------------------------------------------
RunMainLoop:
            Event       equ rbp-64
            push        rbp
            mov         rbp,rsp
            sub         rsp,64
.MainLoop:
            ; process window events
            lea         rdi,[Event]
            call        [SDL_PollEvent]
            cmp         byte [Event],SDL_KEYDOWN
            je          .MainLoopEnd
            ; draw and update
            call        Update
            ; swap
            call        [SDL_GL_SwapBuffers]
            jmp         .MainLoop
.MainLoopEnd:
            mov         rsp,rbp
            pop         rbp
            ret
            restore     Event
;-------------------------------------------------------------------------------
; NAME: Main
; DESC: Program entry point.
;-------------------------------------------------------------------------------
Main:
            call        LoadSDLFunctions
            call        OpenWindow
            call        LoadOGLFunctions
            call        Init
            call        RunMainLoop
            call        [SDL_Quit]
            ; terminate process
            mov         eax,60
            xor         edi,edi
            syscall

segment readable writeable

align 4

g_VP                    dd 0
g_FP                    dd 0
g_VBO                   dd 0
g_VertexData            dd -0.7,-0.7,0.7,-0.7,0.0,0.7
VBO_SIZE                = $ - g_VertexData

g_Time                  dd 0

align 8

g_VBOAddr               dq 0

g_libSDL                dq 0

SDL_Init                dq 0
SDL_Quit                dq 0
SDL_SetVideoMode        dq 0
SDL_PollEvent           dq 0
SDL_GetTicks            dq 0

SDL_GL_LoadLibrary      dq 0
SDL_GL_GetProcAddress   dq 0
SDL_GL_SetAttribute     dq 0
SDL_GL_SwapBuffers      dq 0

glClear                             dq 0
glGenProgramsARB                    dq 0
glBindProgramARB                    dq 0
glNamedProgramStringEXT             dq 0
glGenBuffers                        dq 0
glNamedBufferDataEXT                dq 0
glGetNamedBufferParameterui64vNV    dq 0
glMakeNamedBufferResidentNV         dq 0
glEnable                            dq 0
glEnableClientState                 dq 0
glVertexAttribFormatNV              dq 0
glEnableVertexAttribArray           dq 0
glBufferAddressRangeNV              dq 0
glDrawArrays                        dq 0

segment readable

align 1

g_str_libsdl            db 'libSDL-1.2.so.0',0

g_str_SDL_Init          db 'SDL_Init',0
g_str_SDL_Quit          db 'SDL_Quit',0
g_str_SDL_SetVideoMode  db 'SDL_SetVideoMode',0
g_str_SDL_PollEvent     db 'SDL_PollEvent',0
g_str_SDL_GetTicks      db 'SDL_GetTicks',0

g_str_SDL_GL_LoadLibrary    db 'SDL_GL_LoadLibrary',0
g_str_SDL_GL_GetProcAddress db 'SDL_GL_GetProcAddress',0
g_str_SDL_GL_SetAttribute   db 'SDL_GL_SetAttribute',0
g_str_SDL_GL_SwapBuffers    db 'SDL_GL_SwapBuffers',0

g_str_glClear                               db 'glClear',0
g_str_glGenProgramsARB                      db 'glGenProgramsARB',0
g_str_glBindProgramARB                      db 'glBindProgramARB',0
g_str_glNamedProgramStringEXT               db 'glNamedProgramStringEXT',0
g_str_glGenBuffers                          db 'glGenBuffers',0
g_str_glNamedBufferDataEXT                  db 'glNamedBufferDataEXT',0
g_str_glGetNamedBufferParameterui64vNV      db 'glGetNamedBufferParameterui64vNV',0
g_str_glMakeNamedBufferResidentNV           db 'glMakeNamedBufferResidentNV',0
g_str_glEnable                              db 'glEnable',0
g_str_glEnableClientState                   db 'glEnableClientState',0
g_str_glVertexAttribFormatNV                db 'glVertexAttribFormatNV',0
g_str_glEnableVertexAttribArray             db 'glEnableVertexAttribArray',0
g_str_glBufferAddressRangeNV                db 'glBufferAddressRangeNV',0
g_str_glDrawArrays                          db 'glDrawArrays',0

g_SrcVP:
db '!!NVvp4.0',10
db 'MOV result.position,vertex.attrib[0];'
db 'END',0
SRC_VP_LENGTH = $ - g_SrcVP - 1

g_SrcFP:
db '!!NVfp4.0',10
db 'PARAM c = { 0,1,0,1 };'
db 'MOV result.color,c;'
db 'END',0
SRC_FP_LENGTH = $ - g_SrcFP - 1
